package net.wicp.tams.common.apiext;

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.wicp.tams.common.constant.JvmStatus;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;

/***
 * 暂时默认只支持log4j2 可以通过设置property:"ts.log4j.resource.fileName" 指定log配置文件
 * 
 * @author rjzjh
 *
 */
public class LoggerUtil {
	public static final String TS_LOGGER_NAME = "net.wicp.tams.common.apiext.logger.ext";
	public static final String ENV_FILE_NAME = "logFileName";
	public static final String ENV_FILE_ROOT = "logFilePath";
	public static final String ENV_PATTERN = "loggerPattern";
	private static Logger log;

	static {
		initializeLogger();
	}

	private static void initializeLogger() {
		// 设置文件的根目录
		if (System.getProperty(ENV_FILE_ROOT) == null || "".equals(System.getProperty(ENV_FILE_ROOT))) {
			String logRoot = System.getenv(ENV_FILE_ROOT);
			logRoot = (logRoot == null || "".equals(logRoot)) ? "/alidata1/admin" : logRoot;
			System.setProperty(ENV_FILE_ROOT, logRoot);
		}

		if (System.getProperty(ENV_PATTERN) == null || "".equals(System.getProperty(ENV_PATTERN))) {
			System.setProperty(ENV_PATTERN, "%msg%n");
		}

		String logConfigFilePath = System.getProperty("ts.log.configFile", System.getenv("TS_LOG_CONFIGFILE"));
		Boolean isLoadConfig = Boolean.parseBoolean(System.getProperty("ts.log.loadconfig", "true"));

		final String log4j_resource_file = System.getProperty("ts.log4j.resource.fileName",
				"logger/log4j_ts_clients.xml");
		final String logback_resource_file = System.getProperty("ts.logback.resource.fileName",
				"logger/logback_ts_clients.xml");
		final String log4j2_resource_file = System.getProperty("ts.log4j2.resource.fileName",
				"logger/log4j2_ts_clients.xml");

		if (isLoadConfig) {
			try {
				ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
				Class<?> classType = iLoggerFactory.getClass();
				if (classType.getName().equals("org.slf4j.impl.Log4jLoggerFactory")) {
					Class<?> DOMConfigurator = null;
					Object DOMConfiguratorObj = null;
					DOMConfigurator = Class.forName("org.apache.log4j.xml.DOMConfigurator");
					DOMConfiguratorObj = DOMConfigurator.newInstance();
					if (null == logConfigFilePath) {
						Method configure = DOMConfiguratorObj.getClass().getMethod("configure", URL.class);
						URL url = LoggerUtil.class.getClassLoader().getResource(log4j_resource_file);
						configure.invoke(DOMConfiguratorObj, url);
					} else {
						Method configure = DOMConfiguratorObj.getClass().getMethod("configure", String.class);
						configure.invoke(DOMConfiguratorObj, logConfigFilePath);
					}
				} else if (classType.getName().equals("ch.qos.logback.classic.LoggerContext")) {
					Class<?> joranConfigurator = null;
					Class<?> context = Class.forName("ch.qos.logback.core.Context");
					Object joranConfiguratorObj = null;
					joranConfigurator = Class.forName("ch.qos.logback.classic.joran.JoranConfigurator");
					joranConfiguratorObj = joranConfigurator.newInstance();
					Method setContext = joranConfiguratorObj.getClass().getMethod("setContext", context);
					setContext.invoke(joranConfiguratorObj, iLoggerFactory);
					if (null == logConfigFilePath) {
						URL url = LoggerUtil.class.getClassLoader().getResource(logback_resource_file);
						Method doConfigure = joranConfiguratorObj.getClass().getMethod("doConfigure", URL.class);
						doConfigure.invoke(joranConfiguratorObj, url);
					} else {
						Method doConfigure = joranConfiguratorObj.getClass().getMethod("doConfigure", String.class);
						doConfigure.invoke(joranConfiguratorObj, logConfigFilePath);
					}
				} else if (classType.getName().equals("org.apache.logging.slf4j.Log4jLoggerFactory")) {
					// log4j2 configuration setting
					if (System.getProperty(ENV_FILE_NAME) == null || "".equals(System.getProperty(ENV_FILE_NAME))) {
						System.setProperty(ENV_FILE_NAME, "ts_statistic");
					} else {
						System.setProperty(ENV_FILE_NAME, System.getProperty(ENV_FILE_NAME).replace(".log", ""));
					}

					Class<?> configurationSourceCls = Class
							.forName("org.apache.logging.log4j.core.config.ConfigurationSource");
					Class<?> xmlConfigurationCls = Class
							.forName("org.apache.logging.log4j.core.config.xml.XmlConfiguration");
					Class<?> configurationCls = Class.forName("org.apache.logging.log4j.core.config.Configuration");
					Class<?> loggerContextCls = Class.forName("org.apache.logging.log4j.core.LoggerContext");
					Class<?> log4jLoggerCls = Class.forName("org.apache.logging.slf4j.Log4jLogger");
					Class<?> extendedLoggerCls = Class.forName("org.apache.logging.log4j.spi.ExtendedLogger");

					Constructor<?> configSourceConstructor = configurationSourceCls
							.getDeclaredConstructor(InputStream.class);
					Constructor<?> xmlConfigurationConstructor = xmlConfigurationCls
							.getDeclaredConstructor(configurationSourceCls);
					Constructor<?> loggerContextConstructor = loggerContextCls.getDeclaredConstructor(String.class);
					Constructor<?> log4jLoggerConstructor = log4jLoggerCls.getDeclaredConstructor(extendedLoggerCls,
							String.class);

					InputStream configFileInput = null;
					if (null == logConfigFilePath) {
						configFileInput = LoggerUtil.class.getClassLoader().getResourceAsStream(log4j2_resource_file);
					} else {
						configFileInput = new FileInputStream(new File(logConfigFilePath));
					}
					Object configurationSourceInst = configSourceConstructor.newInstance(configFileInput);
					Object xmlConfigurationInst = xmlConfigurationConstructor.newInstance(configurationSourceInst);
					Object loggerContextInst = loggerContextConstructor.newInstance(LoggerUtil.class.getName());
					Method loggerContextStartMethod = loggerContextCls.getDeclaredMethod("start", configurationCls);
					loggerContextStartMethod.invoke(loggerContextInst, xmlConfigurationInst);
					Method loggerContextGetLoggerMethod = loggerContextCls.getDeclaredMethod("getLogger", String.class);
					log = (Logger) log4jLoggerConstructor.newInstance(
							loggerContextGetLoggerMethod.invoke(loggerContextInst, TS_LOGGER_NAME), TS_LOGGER_NAME);
					return;
				}
			} catch (Exception e) {
				System.err.println(e);
			}
		}
		log = LoggerFactory.getLogger(TS_LOGGER_NAME);
	}

	public static Logger getTamsLogger() {
		return log;
	}

	/***
	 * 退出虚拟机,需延时一段时候，最后一条日志才能打出来。
	 * 
	 * @param jvmStatus
	 */
	public static void exit(JvmStatus jvmStatus) {
		exit(jvmStatus, 50l);
	}

	public static void exit(JvmStatus jvmStatus, long sleeptime) {
		try {
			Thread.sleep(sleeptime);
		} catch (InterruptedException e1) {
		}
		Runtime.getRuntime().exit(jvmStatus.getValue());
	}
}
